package com.peas.platform.module.icims.base.sys.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.peas.platform.common.core.exception.BaseException;
import com.peas.platform.common.core.property.ProjectProperties;
import com.peas.platform.framework.mybatisplus.domain.BaseDomain;
import com.peas.platform.framework.mybatisplus.po.BasePo;
import com.peas.platform.framework.mybatisplus.service.BaseServiceImpl;
import com.peas.platform.module.icims.base.mdm.enums.FileType;
import com.peas.platform.module.icims.base.sys.domain.AttachmentDomain;
import com.peas.platform.module.icims.base.sys.dto.AttachmentDto;
import com.peas.platform.module.icims.base.sys.service.AttachmentService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j
public class AttachmentServiceImpl extends BaseServiceImpl<AttachmentDto> implements AttachmentService {

    @Value("${file.storage:local}")
    private String storage;
    @Value("${file.storage.path:/data}")
    private String storagePath;
    @Value("${spring.application.name}")
    private String springAppName;

    @Resource
    private AttachmentDomain attachmentDomain;
    @Resource
    private ProjectProperties projectProperties;

    @Override
    public BaseDomain<AttachmentDto, ? extends BasePo> getDomain() {
        return attachmentDomain;
    }

    @SneakyThrows
    @Transactional
    @Override
    public AttachmentDto upload(MultipartFile file, FileType fileType) {
        if (fileType == null) {
            fileType = FileType.normal;
        }
        String name = file.getOriginalFilename();
        if (name == null) {
            name = StrUtil.EMPTY;
        }
        if (fileType == FileType.normal && StrUtil.contains(name, '.')) {
            String str = name.substring(name.lastIndexOf('.') + 1).toLowerCase();
            switch (str) {
                case "txt":
                case "text":
                    fileType = FileType.text;
                    break;
                case "pdf":
                    fileType = FileType.document;
                    break;
                case "doc":
                case "docx":
                    fileType = FileType.word;
                    break;
                case "xls":
                case "xlsx":
                    fileType = FileType.excel;
                    break;
                case "ppt":
                case "pptx":
                    fileType = FileType.powerpoint;
                    break;
                case "jpg":
                case "jpeg":
                case "png":
                case "gif":
                case "bmp":
                case "tiff":
                    fileType = FileType.image;
                    break;
                case "mp3":
                case "mid":
                case "wav":
                case "wma":
                    fileType = FileType.voice;
                    break;
                case "mp4":
                case "m4v":
                case "mov":
                case "mkv":
                case "avi":
                case "mpeg":
                case "rmvb":
                    fileType = FileType.video;
                    break;
                case "zip":
                case "7z":
                case "rar":
                case "tar":
                case "gz":
                    fileType = FileType.compress;
                    break;
            }
        }
        String md5 = DigestUtils.md5DigestAsHex(file.getInputStream());
        String bucket = DateUtil.format(DateTime.now(), DatePattern.SIMPLE_MONTH_PATTERN) + "-" + fileType.getKey();
        AttachmentDto c2 = new AttachmentDto();
        c2.setMd5(md5);
        c2.setOriginal(name);
        c2.setBucket(bucket);
        AttachmentDto dto = this.getOne(c2, false);
        if (dto != null) {
            return dto;
        }
        AttachmentDto c1 = new AttachmentDto();
        c1.setMd5(md5);
        AttachmentDto bean = this.getOne(c1, false);
        if (bean == null) {
            String obj = md5 + name.substring(name.lastIndexOf("."));
            if (StrUtil.equals("local", storage)) {
                File dir = new File(storagePath + "/" + bucket);
                boolean bool = dir.mkdirs();
                log.debug("mkdirs:" + bool);
                File f = new File(dir.getPath() + "/" + obj);
                IoUtil.copy(file.getInputStream(), Files.newOutputStream(f.toPath()));
                bean = new AttachmentDto();
                bean.setFileName(obj);
                bean.setBucket(bucket);
                bean.setPath(f.getPath());
                bean.setUrl(null);
            } else {
                throw new BaseException("not supported");
            }
        }
        bean.setId(null);
        bean.setVersion(1);
        bean.setSystem(projectProperties.getBusiness());
        bean.setSystemName(projectProperties.getBusinessName());
        bean.setService(projectProperties.getService());
        bean.setServiceName(projectProperties.getServiceName());
        bean.setFileType(fileType.getKey());
        bean.setMd5(md5);
        bean.setStorage(storage);
        bean.setSize(file.getSize());
        bean.setOriginal(name);
        this.save(bean);
        bean.setUrl("/" + springAppName + "/api/v1/file/preview/" + bean.getId());
        this.updateById(bean);
        return bean;
    }

    @Override
    public InputStream getObject(Long id) {
        return this.getObject(this.getById(id));
    }

    @SneakyThrows
    @Override
    public InputStream getObject(AttachmentDto dto) {
        Assert.notNull(dto, "找不到文件");
        if (StrUtil.equals("local", storage)) {
            String rootPath = System.getProperty("user.dir");
            return Files.newInputStream(Paths.get(rootPath + dto.getPath()));

        }
        throw new BaseException("not supported");
    }

    @SneakyThrows
    @Override
    public void zipFiles(List<AttachmentDto> list, ZipOutputStream zipOutputStream) {
        if (CollUtil.isEmpty(list)) {
            return;
        }
        List<String> names = new ArrayList<>();
        for (AttachmentDto dto : list) {
            String fileName = dto.getOriginal();
            Assert.isTrue(!names.contains(fileName), "附件[{}]重复", fileName);
            names.add(fileName);
            ZipEntry zipEntry = new ZipEntry(fileName);
            zipOutputStream.putNextEntry(zipEntry);
            InputStream in = getObject(dto);
            int len;
            byte[] buf = new byte[8 * 1024];
            while ((len = in.read(buf)) != -1) {
                zipOutputStream.write(buf, 0, len);
            }
        }
    }

}
